Split server upstream transports#10
Merged
Merged
Conversation
monadoid
approved these changes
May 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR turns the transport/client/server split into explicit owning classes, adds the new topology-aware router path, and brings the translated Python and Go surfaces back into line with the TypeScript source for the files marked
MODCDP_TRANSLATE.The main shape is now:
ModCDPClientownslauncher,upstream,injector,router,types,config, and optionalserver_configas concrete component objects/config objects.AutoSessionRouterowns browser target/session/execution-context routing andMod.getTopology.CDPTypesowns native CDP + ModCDP + custom command/event schema registration, runtime validation, JSON-schema normalization, and alias hydration.ModCDPServeris TS-only service-worker code that composes a normal upstreamModCDPClientplus a downstream transport set.Architecture changes
Client composition
js/src/client/ModCDPClient.tsfrom a large option-normalizing client into a component-composed client:launcher: BrowserLauncherupstream: UpstreamTransportinjector: ExtensionInjector | nullrouter: AutoSessionRoutertypes: CDPTypesconfig: ModCDPClientConfigserver_config: ModCDPServerConfig | nullclient.send(...); raw transport access is onclient.upstream.send(...); routed browser sends go throughclient.router.router.router_routesand server configuration underserver_config, matching the same shape that gets sent toMod.configure.Mod.addCustomCommand,Mod.addCustomEvent, andMod.addMiddlewareregistrations now use the sharedCDPTypesregistry so local aliases, service-worker wire registration, and runtime validation stay in one place.CDPTypes registry
js/src/types/CDPTypes.tsand translated equivalents in Python/Go.Mod.*schemas and service-worker expressions,Mod.ping,Mod.configure,Mod.evaluate,Mod.getTopology,Mod.addCustomCommand,Mod.addCustomEvent,Mod.addMiddleware, andMod.pong.toJSON()omits expression bodies from serialized command/middleware config while still reporting registry state counts.AutoSessionRouter and topology
AutoSessionRouterfrom target/session helper state into the owner of browser routing state:sessionId_from_targetIdtargetId_from_sessionIdtargetscontextsTarget.*,Runtime.*, andPage.*invalidation/update events.UpstreamTransport.Runtime.callFunctionOngets an execution context injected only when the browser-owned params do not already specifyobjectId,executionContextId, oruniqueContextId.Mod.getTopology, which builds a single topology result containing:objectGrouprootFrameIdframes: { [frameId]: Frame }roots: { [objectId]: DomRoot }targets: { [targetId]: TargetInfo }contexts: { [contextKey]: ExecutionContext }Server/downstream split
ModCDPServer.tsimplementation with a TS-only service-worker server class that composes:client: ModCDPClientfor browser-target upstream access,downstream: DownstreamTransportSetfor SDK/client-facing downstream connections,client.typesfor command/event/middleware registry state.extension/src/service_worker.tsis now just service-worker bootstrap: instantiatenew ModCDPServer()andawait server.start().DownstreamTransportDownstreamTransportSetReverseWSDownstreamTransportNativeMessagingDownstreamTransportNATSDownstreamTransportModCDPServer, downstream means SDK/client connections into the service worker.ModCDPServer, upstream means browser targets reached throughserver.client.reversewsis a server downstream transport and only a client-side upstream transport.server.downstreammethods/semantics for request handlers, explicit responses, event fanout, client lease tracking, and downstream disconnect browser-close behavior.Transport changes
Shared upstream surface
UpstreamTransportandWSUpstreamTransport.send(...)surface on upstream transports with typed command support, event listeners,getTargets,createTarget,attachToTarget, anddetachFromTargethelpers.UpstreamTransportnow exposespeer_kindso client-side transports that terminate at a ModCDP server peer can bypass local router bootstrap and forward CDP-shaped commands directly.TS-only transports
ChromeDebuggerUpstreamTransport.tsPipeUpstreamTransport.tsReverseWSUpstreamTransport.tsNATSUpstreamTransport.tsNativeMessagingUpstreamTransport.tsNats*toNATS*andReverseWebSocket*toReverseWS*.Config/naming cleanup
launcherupstreaminjectorrouterclient_configserver_configtypesbb/BBBrowserLauncher/BBExtensionInjectorcli/CLIExtensionInjectorcdp/CDPExtensionInjectordiscover/DiscoverExtensionInjectornone/NoneBrowserLauncherws/WSUpstreamTransportlauncher_local_*launcher_remote_*launcher_bb_*injector_cli_*injector_cdp_*injector_bb_*injector_discover_*upstream_ws_*NoopBrowserLauncher,BrowserbaseBrowserLauncher,ExtensionsLoadUnpackedInjector,LocalBrowserLaunchExtensionInjector,DiscoveredExtensionInjector, and translated borrow injection.Cross-language parity
Python
.configreads.CDPTypes,toJSON, topology shapes, router config, and updated ModCDP type models.BBBrowserLauncherNoneBrowserLauncherBBExtensionInjectorCLIExtensionInjectorCDPExtensionInjectorDiscoverExtensionInjectorWSUpstreamTransportGo
CDPTypes,toJSON, topology/config shapes, and translated router/client changes.BBBrowserLauncherNoneBrowserLauncherBBExtensionInjectorCLIExtensionInjectorCDPExtensionInjectorDiscoverExtensionInjectorWSUpstreamTransportTranslation markers
Generated artifacts
js/src/types/generated/aliases.tsjs/src/types/generated/cdp.tsjs/src/types/generated/zod/**python/modcdp/extension.zipgo/modcdp/injector/extension.zipExtension UI/service-worker changes
ModCDPServerinstead of duplicating server bookkeeping inextension/src/service_worker.ts.toJSON()tree with config/state/children instead of dumping a hand-built service-worker status object.Tests and CI
Mod.getTopology.Validation run on the current head:
pnpm run typecheckpnpm run build:packagepnpm exec prek run oxfmt --all-filespnpm exec vitest run js/test/test.ReverseWSUpstreamTransport.ts --fileParallelism=false --maxWorkers=1pnpm exec vitest run js/test/test.proxy.ts --testNamePattern "reversews" --fileParallelism=false --maxWorkers=1cd python && uv run pyrightcd python && uv run ty checkcd go && go test -count=1 ./modcdp ./modcdp/transportThe current PR check suite was green on head
cb4dc17, including the JS/Python/Go test/demo matrix, proxy examples, serialized reversews/NATS JS jobs, andprek.Review guide
Suggested review order:
js/src/types/modcdp.tsandjs/src/types/CDPTypes.tsfor public shapes and registry behavior.js/src/transport/*for upstream/downstream responsibility boundaries.js/src/router/AutoSessionRouter.tsfor target/session/context/topology routing.js/src/server/ModCDPServer.tsandextension/src/service_worker.tsfor the service-worker composition change.js/src/client/ModCDPClient.tsfor constructor/config/send lifecycle changes.MODCDP_TRANSLATEand omit TS-only files.